package config

import (
	"fmt"
	"os"
	"strconv"
)

type Config struct {
	Port                int
	ModelPath           string
	CppBinaryPath       string
	TempDir             string
	ConfidenceThreshold float32
	NMSThreshold        float32
	InputSize           int

	// Model configuration
	ModelVersion   string // YOLOv8, YOLOv11, auto-detect
	NumClasses     int    // Number of classes (0 = auto-detect)
	ClassNamesFile string // Path to custom class names file

	// Text detection configuration
	TextDetectionModelPath   string
	TextDetectionConfidence  float32
	TextDetectionMaxRegions  int
	TextDetectionOutputDir   string
	TextDetectionSaveRegions bool

	// OpenVINO device configuration
	OpenVINODevice     string // AUTO, GPU, NPU, CPU
	OpenVINONumThreads int    // Number of threads for CPU (0 = auto)
	OpenVINOGPUStreams int    // Number of GPU streams (0 = auto)
	OpenVINONPUStreams int    // Number of NPU streams (0 = auto)
}

func LoadConfig() (*Config, error) {
	cfg := &Config{
		Port:                getEnvInt("PORT", 8080),
		ModelPath:           getEnvString("MODEL_PATH", "./model/yolov8n.xml"),
		CppBinaryPath:       getEnvString("CPP_BINARY_PATH", "./bin/detect_service"),
		TempDir:             getEnvString("TEMP_DIR", "/tmp/yolov8_inference"),
		ConfidenceThreshold: getEnvFloat("CONFIDENCE_THRESHOLD", 0.5),
		NMSThreshold:        getEnvFloat("NMS_THRESHOLD", 0.5),
		InputSize:           getEnvInt("INPUT_SIZE", 640),

		// Model configuration
		ModelVersion:   getEnvString("MODEL_VERSION", "auto"),
		NumClasses:     getEnvInt("NUM_CLASSES", 0),
		ClassNamesFile: getEnvString("CLASS_NAMES_FILE", ""),

		// Text detection configuration
		TextDetectionModelPath:   getEnvString("TEXT_DETECTION_MODEL_PATH", "/models/text-detection-0004.xml"),
		TextDetectionConfidence:  getEnvFloat("TEXT_DETECTION_CONFIDENCE", 0.5),
		TextDetectionMaxRegions:  getEnvInt("TEXT_DETECTION_MAX_REGIONS", 100),
		TextDetectionOutputDir:   getEnvString("TEXT_DETECTION_OUTPUT_DIR", "/tmp/text_regions"),
		TextDetectionSaveRegions: getEnvBool("TEXT_DETECTION_SAVE_REGIONS", true),

		// OpenVINO device configuration
		OpenVINODevice:     getEnvString("OPENVINO_DEVICE", "AUTO"),
		OpenVINONumThreads: getEnvInt("OPENVINO_NUM_THREADS", 0),
		OpenVINOGPUStreams: getEnvInt("OPENVINO_GPU_STREAMS", 0),
		OpenVINONPUStreams: getEnvInt("OPENVINO_NPU_STREAMS", 0),
	}

	// Validate configuration
	if err := cfg.Validate(); err != nil {
		return nil, err
	}

	// Create temp directory if it doesn't exist
	if err := os.MkdirAll(cfg.TempDir, 0755); err != nil {
		return nil, fmt.Errorf("failed to create temp directory: %w", err)
	}

	return cfg, nil
}

func (c *Config) Validate() error {
	if c.ModelPath == "" {
		return fmt.Errorf("MODEL_PATH is required")
	}
	if c.CppBinaryPath == "" {
		return fmt.Errorf("CPP_BINARY_PATH is required")
	}
	if c.Port <= 0 || c.Port > 65535 {
		return fmt.Errorf("PORT must be between 1 and 65535")
	}
	if c.ConfidenceThreshold < 0 || c.ConfidenceThreshold > 1 {
		return fmt.Errorf("CONFIDENCE_THRESHOLD must be between 0 and 1")
	}
	if c.NMSThreshold < 0 || c.NMSThreshold > 1 {
		return fmt.Errorf("NMS_THRESHOLD must be between 0 and 1")
	}
	if c.InputSize <= 0 {
		return fmt.Errorf("INPUT_SIZE must be positive")
	}
	return nil
}

func getEnvString(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func getEnvInt(key string, defaultValue int) int {
	if value := os.Getenv(key); value != "" {
		if intVal, err := strconv.Atoi(value); err == nil {
			return intVal
		}
	}
	return defaultValue
}

func getEnvFloat(key string, defaultValue float32) float32 {
	if value := os.Getenv(key); value != "" {
		if floatVal, err := strconv.ParseFloat(value, 32); err == nil {
			return float32(floatVal)
		}
	}
	return defaultValue
}

func getEnvBool(key string, defaultValue bool) bool {
	if value := os.Getenv(key); value != "" {
		if boolVal, err := strconv.ParseBool(value); err == nil {
			return boolVal
		}
	}
	return defaultValue
}
